package project.web.auth;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import online.model.ModelUtil;
import online.model.check.InputCheck;
import online.model.session.SessionAttribute;
import online.model.session.SessionUser;
import online.struts.action.UniForm;
import online.struts.mapping.RequestMapping;
import project.auth.Authentication;
import project.auth.SessionInfo;
import project.auth.SessionInfo.LogoffType;
import project.check.range.LengthRangeCheck;
import project.master.MsgUtil;
import project.web.InstanceFactory;
import core.config.Factory;


/**
 * ログオンアクションクラス
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class LogonActionImpl extends LogonAction {

	/** タグ ユーザID */
	private static final String TAG_UID = "Uid";
	/** ユーザー情報　パスワード*/
	private static final String TAG_PWD = "Pwd";

	/** 別セションログオンメッセージ */
	private static final String MSGID_COLL_LOGON = "ZZ000000004";
	/** ユーザID、パスワードエラーメッセージ */
	private static final String MSGID_NOT_USER = "ZZ000000001";

	/**
	 * ログオン主処理
	 *
	 * @param mapping ActionMappingオブジェクト
	 * @param uf 汎用フォーム
	 * @param request HttpServletRequestオブジェクト
	 * @param response HttpServletResponseオブジェクト
	 * @return 処理結果
	 */
	@Override
	public String perform(final RequestMapping mapping,
			final UniForm uf, final HttpServletRequest request,
			final HttpServletResponse response) {

		if (uf.getSessionUser() != null) {
			return "LOGONED";
		}

		InputCheck ic = InstanceFactory.create(InputCheck.class, uf);
		ic.add(TAG_UID, new LengthRangeCheck(0, 64));
		ic.add(TAG_PWD, new LengthRangeCheck(0, 64));
		ic.populate();

		// 初期表示
		if (!uf.containsKey(TAG_UID) || !uf.containsKey(TAG_PWD)) {
			return ID_VIEW;
		}

		// ログオン処理
		Authentication auth = Factory.create(Authentication.class);
		if (!auth.logon(uf.getString(TAG_UID), uf.getString(TAG_PWD))) {
			MsgUtil.putTopMessage(uf, MSGID_NOT_USER);
			MsgUtil.putMessage(uf, TAG_UID, MSGID_NOT_USER);
			MsgUtil.putMessage(uf, TAG_PWD, MSGID_NOT_USER);
			return ID_VIEW;
		}

		// セション取得
		Map<String, Object> map = invalidateSession(request.getSession(false));
		HttpSession session = request.getSession();
		setSessionObject(session, map);

		// ログオン情報設定
		SessionInfo li = auth.updateStatus(uf.getString(TAG_UID),
				uf.getDateTime(), session.getId(), session.getMaxInactiveInterval());

		// 強制ログアウト時
		if (LogoffType.TYPE_FORCE.equals(li.getLogoffType())) {
			// メッセージ設定
			MsgUtil.putTopMessage(uf, MSGID_COLL_LOGON);
		}

		// セションに情報設定
		// モデル作成
		SessionUser m = new SessionUser.Builder(uf.getString(TAG_UID)).build();
		// セション情報保存
		SessionAttribute.setSessionUser(request, m);
		uf.setSessionUser(m);

		// ログオン情報設定
		setLogonInfoToSession(li, uf, session);

		return ID_OK;
	}

	/**
	 * セション無効化
	 * @param session HttpSession
	 * @return セション保存オブジェクト
	 */
	private Map<String, Object> invalidateSession(final HttpSession session) {
		Map<String, Object> map = new HashMap<>();
		if (session != null) {
			Enumeration<String> e = session.getAttributeNames();
			while (e.hasMoreElements()) {
				String name = e.nextElement();
				map.put(name, session.getAttribute(name));
			}
			session.invalidate();
		}
		return map;
	}

	/**
	 * セションオブジェクト設定
	 * @param session HttpSession
	 * @param map セションオブジェクト保持マップ
	 */
	private void setSessionObject(final HttpSession session, final Map<String, Object> map) {
		for (final Entry<String, Object> me : map.entrySet()) {
			session.setAttribute(me.getKey(), me.getValue());
		}
	}

	/**
	 * ログオン情報設定
	 *
	 * @param li ログオン情報
	 * @param uf 汎用フォーム
	 * @param session セションオブジェクト
	 */
	protected void setLogonInfoToSession(final SessionInfo li,
			final UniForm uf, final HttpSession session) {
		// ログオン時間
		session.setAttribute(TAG_LOGON_TIME, li.getLogonDateTime());
		// ログオフ時間
		session.setAttribute(TAG_LOGOFF_TIME, li.getLogoffDateTime());
		// ログオフ形態
		session.setAttribute(TAG_LOGOFF_TYPE, li.getLogoffType());
		// メッセージ
		session.setAttribute(ModelUtil.TAG_MESSAGE, uf.getStringArray(ModelUtil.TAG_MESSAGE));
		session.setAttribute(ModelUtil.TAG_STATUS, uf.getStringArray(ModelUtil.TAG_STATUS));
	}
}
